import { useCallback, useEffect, useRef, useState } from 'react';

import { PubSub, PubSubError } from './pubsub';

export interface Action<T = unknown> {
  type: string;
  payload?: T;
  meta?: Record<string, unknown>;
  error?: boolean;
}

export type Reducer<S, A extends Action> = (state: S, action: A) => S;

export type MiddlewareAPI<S, A extends Action> = {
  getState: () => S;
  dispatch: (action: A) => void;
};

export type NextFunction<A extends Action> = (action: A) => void;
export type Middleware<S, A extends Action> = (
  api: MiddlewareAPI<S, A>,
) => (next: NextFunction<A>) => NextFunction<A>;

export class StoreError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'StoreError';
  }
}

export class Store<S, A extends Action> {
  private state: S;
  private reducer: Reducer<S, A>;
  private pubsub: PubSub<S>;
  private middlewares: Array<(next: NextFunction<A>) => NextFunction<A>>;
  private isDispatching: boolean;

  constructor(reducer: Reducer<S, A>, initialState: S) {
    this.state = initialState;
    this.reducer = reducer;
    this.pubsub = new PubSub<S>();
    this.middlewares = [];
    this.isDispatching = false;
  }

  getState(): S {
    return this.state;
  }

  dispatch(action: A): void {
    if (this.isDispatching) {
      throw new StoreError('Reducers may not dispatch actions.');
    }

    try {
      this.isDispatching = true;

      // 创建中间件链
      const chain = this.middlewares.slice();

      const composedMiddleware = chain.reduce(
        (composed, middleware) => {
          return middleware(composed);
        },
        (action: A) => {
          // 基础 dispatch 逻辑
          const nextState = this.reducer(this.state, action);
          this.state = nextState;
          this.pubsub.publish('stateChange', this.state);
        },
      );

      // 执行中间件链
      composedMiddleware(action);
    } catch (error) {
      console.error('Error in dispatch:', error);
      throw new StoreError(
        `Error dispatching action: ${error instanceof Error ? error.message : String(error)}`,
      );
    } finally {
      this.isDispatching = false;
    }
  }

  subscribe(listener: (state: S) => void): () => void {
    try {
      return this.pubsub.subscribe('stateChange', listener);
    } catch (error) {
      if (error instanceof PubSubError) {
        throw new StoreError(error.message);
      }
      throw error;
    }
  }

  addMiddleware(middleware: Middleware<S, A>): void {
    const middlewareAPI: MiddlewareAPI<S, A> = {
      getState: () => this.state,
      dispatch: (action: A) => this.dispatch(action),
    };

    this.middlewares.push(middleware(middlewareAPI));
  }
}

// 创建自定义Hook用于在React组件中使用Store
export function createStoreHook<S, A extends Action>(store: Store<S, A>) {
  return function useStore(): [S, (action: A) => void, Store<S, A>] {
    const [state, setState] = useState<S>(store.getState());
    const isMounted = useRef(true);

    useEffect(() => {
      // 组件挂载时订阅状态变化
      const unsubscribe = store.subscribe(newState => {
        if (isMounted.current) {
          setState(newState);
        }
      });

      // 组件卸载时清理
      return () => {
        isMounted.current = false;
        unsubscribe();
      };
    }, []);

    const dispatch = useCallback((action: A) => {
      if (isMounted.current) {
        try {
          store.dispatch(action);
        } catch (error) {
          console.error('Error dispatching action:', error);
          // 可以在这里添加错误处理逻辑
        }
      }
    }, []);

    return [state, dispatch, store];
  };
}

// 示例用法
export interface CounterState {
  count: number;
  lastUpdated: number;
}

export interface CounterAction extends Action {
  type: 'INCREMENT' | 'DECREMENT' | 'RESET';
  payload?: number;
}

// 修改日志中间件的实现
export const loggerMiddleware: Middleware<CounterState, CounterAction> = api => next => action => {
  console.log('dispatching', action);
  console.log('prev state', api.getState());
  next(action);
  console.log('next state', api.getState());
};

const counterReducer: Reducer<CounterState, CounterAction> = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return {
        count: state.count + (action.payload || 1),
        lastUpdated: Date.now(),
      };
    case 'DECREMENT':
      return {
        count: state.count - (action.payload || 1),
        lastUpdated: Date.now(),
      };
    case 'RESET':
      return {
        count: 0,
        lastUpdated: Date.now(),
      };
    default:
      return state;
  }
};

export const createCounterStore = () => {
  const store = new Store(counterReducer, { count: 0, lastUpdated: Date.now() });
  store.addMiddleware(loggerMiddleware);
  return store;
};
